package google

import (
	"errors"
	"fmt"
	"go.manyji.com/lib/config"
	"go.manyji.com/lib/json"
	"io"
	"net/http"
	"net/url"
	"sync"
	"time"
)

var (
	clientID     = *config.String("google.clientId", "943050745818-l008482gu0i30gst6jgeegjda4feh658.apps.googleusercontent.com", "google 开发者 clientId")
	clientSecret = *config.String("google.clientSecret", "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", "google 开发者 clientSecret")
	accessToken  = sync.Map{}
)

func RefreshTokenSchedule() {

	for {
		<-time.After(time.Second * 10)
		accessToken.Range(func(key, value any) bool {
			now := time.Now().Unix()
			tokenInfo := value.(*GoogleAccessToken)
			/* 距离 token 过期 还差300秒的时候，刷新token */
			if tokenInfo.Expired-now < 300 {
				gat, err := refreshGoogleAccessToken(tokenInfo.RefreshToken)
				if err == nil {
					tokenInfo.Expired = gat.Expired
					tokenInfo.AccessToken = gat.AccessToken
				}
			}
			return true
		})
	}
}

func GetUserProfile(authorizationCode, redirectURI string) (*UserProfile, error) {

	gat, err := getGoogleAccessToken(authorizationCode, redirectURI)
	if err != nil {
		return nil, err
	}

	up, err := getUserProfile(gat.AccessToken)
	if err != nil {
		return nil, err
	}

	return up, nil
}

func getUserProfile(accessToken string) (*UserProfile, error) {

	client := &http.Client{}

	// 创建一个HTTP GET请求
	req, err := http.NewRequest("GET", "https://www.googleapis.com/oauth2/v1/userinfo", nil)
	if err != nil {
		return nil, err
	}
	// 设置自定义请求头
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", accessToken))

	// 发起请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp == nil {
		return nil, nil
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	emptyUp := UserProfile{}
	up := emptyUp
	upError := UserProfileError{}
	if err = json.Unmarshal(body, &up); err != nil {
		return nil, err
	} else {
		if up == emptyUp {
			_ = json.Unmarshal(body, &upError)
			return nil, errors.New(upError.Error.Message)
		}
	}

	return &up, nil
}

/* 获取 google access_token */
func GetGoogleAccessToken(authorizationCode, redirectURI string) (*GoogleAccessToken, error) {

	var (
		err error
		gat *GoogleAccessToken
	)

	accessToken.Range(func(key, value any) bool {

		tokenInfo := value.(*GoogleAccessToken)
		gat = tokenInfo
		return false
	})

	if gat == nil {
		gat, err = getGoogleAccessToken(authorizationCode, redirectURI)
		if err == nil && gat.AccessToken != "" {
			accessToken.Store(gat.AccessToken, gat)
		}
	}

	return gat, err
}

func getGoogleAccessToken(authorizationCode, redirectURI string) (*GoogleAccessToken, error) {

	data := url.Values{}
	data.Set("code", authorizationCode)
	data.Set("client_id", clientID)
	data.Set("client_secret", clientSecret)
	data.Set("redirect_uri", redirectURI)
	data.Set("grant_type", "authorization_code")

	resp, err := http.PostForm("https://oauth2.googleapis.com/token", data)
	if err != nil {
		return nil, err
	}

	if resp == nil {
		return nil, nil
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	gat := &GoogleAccessToken{}
	gatError := &GoogleAccessTokenErr{}
	if err = json.Unmarshal(body, gat); err != nil {
		return nil, err
	} else {
		if gat.AccessToken == "" {
			_ = json.Unmarshal(body, gatError)
			return nil, errors.New(gatError.Error)
		}
	}

	gat.RedirectURI = redirectURI
	gat.Expired = time.Now().Unix() + int64(gat.ExpiresIn)
	return gat, nil
}

/* 刷新 google access_token */
func refreshGoogleAccessToken(refreshToken string) (*GoogleAccessToken, error) {

	data := url.Values{}
	data.Set("refresh_token", refreshToken)
	data.Set("client_id", clientID)
	data.Set("client_secret", clientSecret)
	data.Set("grant_type", "refresh_token")

	resp, err := http.PostForm("https://www.googleapis.com/oauth2/v3/token", data)
	if err != nil {
		return nil, err
	}

	if resp == nil {
		return nil, nil
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	gat := &GoogleAccessToken{}
	gatError := &GoogleAccessTokenErr{}
	if err = json.Unmarshal(body, gat); err != nil {
		return nil, err
	} else {
		if gat.AccessToken == "" {
			_ = json.Unmarshal(body, gatError)
			return nil, errors.New(gatError.Error)
		}
	}

	gat.Expired = time.Now().Unix() + int64(gat.ExpiresIn)
	return gat, nil
}
